use crate::WebResponseSupportTrait;
use salvo::{handler, Depot, Request, Response};
use serde_json::Value;
use std::collections::HashMap;
use std::convert::From;
use std::str::FromStr;
use std::sync::Arc;
use visit_dd_core::base64ct::Encoding;
use visit_dd_core::gateway::{ClientToken, RecordAction, C_TT_ANO};
use visit_dd_core::i18n_text::{E_ARG_BAD, E_ARG_MISS};
use visit_dd_core::proj::APP_CONFIG;
use visit_dd_core::query::QueryFilter;
use visit_dd_core::record::VddRecord;
use visit_dd_core::{i18n, Astr, FieldId, ProjectRsaHelper};
use visit_dd_db::record_db::RecordDbTrait;
use visit_dd_db::{cache, field_db, gateway_db, model_db, record_db, value_db};

const E_TOKEN_SALT: &str = "加密盐传值不合法，只能传6位正整数";

#[derive(Debug)]
struct GatewayClient {
    pub tk: ClientToken,
    pub model_tag: Astr,
    pub http_body: Option<Value>,
}

impl GatewayClient {
    /// 从客户端请求中提取出凭据
    fn extract_token(req: &mut Request) -> Result<ClientToken, Astr> {
        let tt = req.header::<String>("Token-Type");
        if tt.is_none() {
            return Err("认证方式未传值".into());
        }
        let tt = tt.unwrap();
        let tt = u8::from_str(&tt);
        if tt.is_err() {
            return Err("认证方式指定不合法,只能传值0～3".into());
        }
        let tt = tt.unwrap();
        if tt > 5 {
            return Err("认证方式指定不合法,只能传值0～3".into());
        }
        if tt != C_TT_ANO {
            let salt = req.header::<String>("Token-Salt");
            if salt.is_none() {
                return Err("加密盐未传值".into());
            }
            let salt = salt.unwrap();
            let salt = u32::from_str(&salt);
            if salt.is_err() {
                return Err(E_TOKEN_SALT.into());
            }
            let salt = salt.unwrap();
            if salt < 100000 || salt > 999999 {
                return Err(E_TOKEN_SALT.into());
            }
            let hash = req.header::<String>("Token-Hash");
            if hash.is_none() {
                return Err("加密值未传值".into());
            }
            let hash = hash.unwrap();
            if hash.len() != 64 {
                return Err("加密值不合法，应为sha256消息摘要结果".into());
            }
            Ok(ClientToken {
                token_type: tt,
                hash: Some(Arc::from(hash)),
                salt: Some(salt),
            })
        } else {
            Ok(ClientToken {
                token_type: tt,
                hash: None,
                salt: None,
            })
        }
    }
    ///
    pub async fn form_request(req: &mut Request, need_decrypt: bool) -> Result<Self, Astr> {
        let tk = Self::extract_token(req);
        if tk.is_err() {
            return Err(Arc::from(tk.unwrap_err()));
        }
        let tk = tk?;
        let model_tag = req.param::<String>("model-tag");
        if model_tag.is_none() {
            return Err(Arc::from(i18n!(E_ARG_MISS).as_ref()));
        }
        let model_tag = Arc::from(model_tag.unwrap());
        let j = decode_body(req, need_decrypt).await?;
        Ok(GatewayClient {
            tk,
            model_tag,
            http_body: if j.is_null() { None } else { Some(j) },
        })
    }
}

/// 外部访问模型数据
#[handler]
pub(crate) async fn read_record_page(req: &mut Request, _depot: &mut Depot, res: &mut Response) {
    let client = GatewayClient::form_request(req, false).await;
    if client.is_err() {
        res.error(&client.unwrap_err());
        return;
    }
    let client = client.unwrap();
    let sqp = gateway_db::sqp_from_gateway_json(
        &client.http_body.unwrap(),
        &client.tk,
        &client.model_tag,
        true,
    )
    .await;
    if sqp.is_err() {
        res.error(&sqp.unwrap_err());
    } else {
        let sqp = sqp.unwrap();
        let record_vec = gateway_db::get_page_for_gateway(&sqp).await;
        res.ok(&record_vec);
    }
}

/// 从body中提取出json
async fn decode_body(req: &mut Request, need_decrypt: bool) -> Result<Value, Astr> {
    let bytes = req.payload_with_max_size(4 * 1024 * 1024).await;
    match bytes {
        Err(e) => Err(e.to_string().into()),
        Ok(bytes) => {
            if bytes.is_empty() {
                Ok(Value::Null)
            } else {
                let mut b64str_body = String::from_utf8(bytes.to_vec()).unwrap();
                // println!("{}", b64str_body);
                // 经过解密
                if need_decrypt {
                    let security_helper =
                        ProjectRsaHelper::init(&APP_CONFIG.pri_key, &APP_CONFIG.pub_key);
                    b64str_body = security_helper.decode_b64str(&b64str_body)?;
                } else {
                    let buffer = visit_dd_core::base64ct::Base64::decode_vec(&b64str_body);
                    b64str_body = String::from_utf8(buffer.unwrap()).unwrap();
                }
                let value = serde_json::from_str::<Value>(&b64str_body).unwrap();
                Ok(value)
            }
        }
    }
}

/// 添加模型数据的api
#[handler]
pub(crate) async fn append_records(req: &mut Request, _depot: &mut Depot, res: &mut Response) {
    let client = GatewayClient::form_request(req, true).await;
    if client.is_err() {
        res.error(&client.unwrap_err());
        return;
    }
    let client = client.unwrap();
    let http_body = client.http_body.clone().unwrap();
    let schema = gateway_db::try_to_schema(&http_body, &client.model_tag, false).await;
    if schema.is_err() {
        res.error(&schema.unwrap_err());
        return;
    }
    let schema = schema.unwrap();
    let vg = gateway_db::try_to_vg(&client.tk, &schema.model).await;
    if vg.is_none() {
        res.error(i18n!(1101).as_ref());
        return;
    }
    let vg = vg.unwrap();
    //读json中的记录，写入rocksdb
    if http_body.get("records").is_none() {
        res.error(i18n!(E_ARG_BAD).as_ref());
        return;
    }
    let tag_field_map = field_db::f_select_tagged_in_model(schema.model.id).await;
    let mut rec_vec = Vec::<VddRecord>::new();
    let mut err_str = String::new();
    http_body["records"]
        .as_array()
        .unwrap()
        .iter()
        .for_each(|j| {
            let record = VddRecord::from_json(&vg, j, &tag_field_map);
            if record.is_err() {
                err_str.push_str(&record.unwrap_err());
            } else {
                let mut rec = record.unwrap();
                let r = rec.fit_field_defines(&schema, false);
                if r.is_ok() {
                    rec_vec.push(rec);
                } else {
                    err_str.push_str(&r.unwrap_err());
                }
            }
        });
    if err_str.is_empty() {
        let r_vec = gateway_db::append_some(&schema, &mut rec_vec, &vg).await;
        res.ok(&r_vec);
    } else {
        res.error(&err_str);
    }
}

/// 修改模型数据的api
#[handler]
pub(crate) async fn modify_records(req: &mut Request, res: &mut Response) {
    let client = GatewayClient::form_request(req, true).await;
    if client.is_err() {
        res.error(&client.unwrap_err());
        return;
    }
    let client = client.unwrap();
    let http_body = client.http_body.clone().unwrap();
    let actions_j = http_body["actions"].as_array();
    if actions_j.is_none() {
        res.error(i18n!(E_ARG_BAD).as_ref());
        return;
    };
    let actions_j = actions_j.unwrap();
    let schema = gateway_db::try_to_schema(&http_body, &client.model_tag, false).await;
    if schema.is_err() {
        res.error(&schema.unwrap_err());
        return;
    }
    let schema = schema.unwrap();
    let vg = gateway_db::try_to_vg(&client.tk, &schema.model).await;
    if vg.is_none() {
        res.error(i18n!(1101).as_ref());
        return;
    }
    let vg = vg.unwrap();
    let tag_field_map = field_db::f_select_tagged_in_model(schema.model.id).await;
    let actions = RecordAction::batch_from_json(&actions_j, &tag_field_map);
    if actions.is_err() {
        res.error(&actions.unwrap_err());
        return;
    }
    let actions = actions.unwrap();
    let r = gateway_db::execute_gateway_actions(&actions, &schema, &vg).await;
    res.ok(&r);
}

/// 检验某条记录是否存在
#[handler]
pub(crate) async fn check_records(req: &mut Request, res: &mut Response) {
    let client = GatewayClient::form_request(req, false).await;
    if client.is_err() {
        res.error(&client.unwrap_err());
        return;
    }
    let client = client.unwrap();
    // tracing::info!("{:?}", client.j);
    let filters = QueryFilter::batch_from_json(&client.http_body.unwrap());
    if filters.len() < 1 {
        res.error(i18n!(E_ARG_MISS).as_ref());
        return;
    }
    // tracing::info!("{:?}", filters);
    let r = gateway_db::check_record_exist(&client.model_tag, &filters).await;
    res.wrap(r);
}

/// 获取某个模型某个字段的全部值
#[handler]
pub(crate) async fn export_fv(req: &mut Request, res: &mut Response) {
    let client = GatewayClient::form_request(req, false).await;
    if client.is_err() {
        res.error(&client.unwrap_err());
        return;
    }
    let client = client.unwrap();
    let model = model_db::m_load_by_tag(&client.model_tag).await;
    if model.is_none() {
        res.error("传入的模型标记错误");
        return;
    }
    let model = model.unwrap();
    let schema = cache::get_schema(model.id).await.unwrap();
    let field = req.query::<String>("field").unwrap();
    let field = schema.tags.iter().find(|x| x.1.as_ref() == &field).unwrap();
    let values = value_db::fv_select_all(&FieldId(*field.0));
    if values.is_err() {
        res.error(&values.unwrap_err());
    } else {
        let r = values
            .unwrap()
            .iter()
            .map(|x| x.value.get_simple_display())
            .collect::<Vec<Astr>>();
        res.ok(&r);
    }
}

/// 获取某个模型某个字段的分组值
#[handler]
pub(crate) async fn export_grouped_fv(req: &mut Request, res: &mut Response) {
    let client = GatewayClient::form_request(req, false).await;
    if client.is_err() {
        res.error(&client.unwrap_err());
        return;
    }
    let client = client.unwrap();
    let model = model_db::m_load_by_tag(&client.model_tag).await;
    if model.is_none() {
        res.error("传入的模型标记错误");
        return;
    }
    let model = model.unwrap();
    let schema = cache::get_schema(model.id).await.unwrap();
    let j = client.http_body.expect(&i18n!(E_ARG_BAD));
    let kf = j["kf"].as_str().expect(&i18n!(E_ARG_BAD));
    let vf = j["vf"].as_str().expect(&i18n!(E_ARG_BAD));
    let k_field = schema
        .tags
        .iter()
        .find(|x| x.1.as_ref() == kf)
        .expect(&i18n!(E_ARG_BAD));
    let k_field = FieldId(*k_field.0);
    let v_field = schema
        .tags
        .iter()
        .find(|x| x.1.as_ref() == vf)
        .expect(&i18n!(E_ARG_BAD));
    let v_field = FieldId(*v_field.0);
    let records = record_db::select_records_all(model.id).await;
    let mut re_map = HashMap::<Astr, Vec<Astr>>::new();
    records.iter().for_each(|record| {
        let k = record.get_value(&k_field).get_simple_display();
        if !re_map.contains_key(&k) {
            re_map.insert(k.clone(), Vec::<Astr>::new());
        }
        re_map
            .get_mut(&k)
            .unwrap()
            .push(record.get_value(&v_field).get_simple_display());
    });
    res.ok(&re_map);
}
